home *** CD-ROM | disk | FTP | other *** search
/ Freelog 115 / FreelogNo115-MaiJuin2013.iso / Internet / AvantBrowser / asetup.exe / _data / webkit / chrome_100_percent.pak / Unnamed File 000009.txt < prev    next >
Text File  |  2013-04-03  |  17KB  |  511 lines

  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4.  
  5. // -----------------------------------------------------------------------------
  6. // NOTE: If you change this file you need to touch renderer_resources.grd to
  7. // have your change take effect.
  8. // -----------------------------------------------------------------------------
  9.  
  10. //==============================================================================
  11. // This file contains a class that implements a subset of JSON Schema.
  12. // See: http://www.json.com/json-schema-proposal/ for more details.
  13. //
  14. // The following features of JSON Schema are not implemented:
  15. // - requires
  16. // - unique
  17. // - disallow
  18. // - union types (but replaced with 'choices')
  19. //
  20. // The following properties are not applicable to the interface exposed by
  21. // this class:
  22. // - options
  23. // - readonly
  24. // - title
  25. // - description
  26. // - format
  27. // - default
  28. // - transient
  29. // - hidden
  30. //
  31. // There are also these departures from the JSON Schema proposal:
  32. // - function and undefined types are supported
  33. // - null counts as 'unspecified' for optional values
  34. // - added the 'choices' property, to allow specifying a list of possible types
  35. //   for a value
  36. // - by default an "object" typed schema does not allow additional properties.
  37. //   if present, "additionalProperties" is to be a schema against which all
  38. //   additional properties will be validated.
  39. //==============================================================================
  40.  
  41. var chromeHidden = requireNative('chrome_hidden').GetChromeHidden();
  42.  
  43. function isInstanceOfClass(instance, className) {
  44.   if (!instance)
  45.     return false;
  46.  
  47.   if (Object.prototype.toString.call(instance) == "[object " + className + "]")
  48.     return true;
  49.  
  50.   return isInstanceOfClass(Object.getPrototypeOf(instance), className);
  51. }
  52.  
  53. function isOptionalValue(value) {
  54.   return typeof(value) === 'undefined' || value === null;
  55. }
  56.  
  57. /**
  58.  * Validates an instance against a schema and accumulates errors. Usage:
  59.  *
  60.  * var validator = new chromeHidden.JSONSchemaValidator();
  61.  * validator.validate(inst, schema);
  62.  * if (validator.errors.length == 0)
  63.  *   console.log("Valid!");
  64.  * else
  65.  *   console.log(validator.errors);
  66.  *
  67.  * The errors property contains a list of objects. Each object has two
  68.  * properties: "path" and "message". The "path" property contains the path to
  69.  * the key that had the problem, and the "message" property contains a sentence
  70.  * describing the error.
  71.  */
  72. chromeHidden.JSONSchemaValidator = function() {
  73.   this.errors = [];
  74.   this.types = [];
  75. };
  76.  
  77. chromeHidden.JSONSchemaValidator.messages = {
  78.   invalidEnum: "Value must be one of: [*].",
  79.   propertyRequired: "Property is required.",
  80.   unexpectedProperty: "Unexpected property.",
  81.   arrayMinItems: "Array must have at least * items.",
  82.   arrayMaxItems: "Array must not have more than * items.",
  83.   itemRequired: "Item is required.",
  84.   stringMinLength: "String must be at least * characters long.",
  85.   stringMaxLength: "String must not be more than * characters long.",
  86.   stringPattern: "String must match the pattern: *.",
  87.   numberFiniteNotNan: "Value must not be *.",
  88.   numberMinValue: "Value must not be less than *.",
  89.   numberMaxValue: "Value must not be greater than *.",
  90.   numberIntValue: "Value must fit in a 32-bit signed integer.",
  91.   numberMaxDecimal: "Value must not have more than * decimal places.",
  92.   invalidType: "Expected '*' but got '*'.",
  93.   invalidChoice: "Value does not match any valid type choices.",
  94.   invalidPropertyType: "Missing property type.",
  95.   schemaRequired: "Schema value required.",
  96.   unknownSchemaReference: "Unknown schema reference: *.",
  97.   notInstance: "Object must be an instance of *."
  98. };
  99.  
  100. /**
  101.  * Builds an error message. Key is the property in the |errors| object, and
  102.  * |opt_replacements| is an array of values to replace "*" characters with.
  103.  */
  104. chromeHidden.JSONSchemaValidator.formatError = function(key, opt_replacements) {
  105.   var message = this.messages[key];
  106.   if (opt_replacements) {
  107.     for (var i = 0; i < opt_replacements.length; i++) {
  108.       message = message.replace("*", opt_replacements[i]);
  109.     }
  110.   }
  111.   return message;
  112. };
  113.  
  114. /**
  115.  * Classifies a value as one of the JSON schema primitive types. Note that we
  116.  * don't explicitly disallow 'function', because we want to allow functions in
  117.  * the input values.
  118.  */
  119. chromeHidden.JSONSchemaValidator.getType = function(value) {
  120.   var s = typeof value;
  121.  
  122.   if (s == "object") {
  123.     if (value === null) {
  124.       return "null";
  125.     } else if (Object.prototype.toString.call(value) == "[object Array]") {
  126.       return "array";
  127.     } else if (typeof(ArrayBuffer) != "undefined" &&
  128.                value.constructor == ArrayBuffer) {
  129.       return "binary";
  130.     }
  131.   } else if (s == "number") {
  132.     if (value % 1 == 0) {
  133.       return "integer";
  134.     }
  135.   }
  136.  
  137.   return s;
  138. };
  139.  
  140. /**
  141.  * Add types that may be referenced by validated schemas that reference them
  142.  * with "$ref": <typeId>. Each type must be a valid schema and define an
  143.  * "id" property.
  144.  */
  145. chromeHidden.JSONSchemaValidator.prototype.addTypes = function(typeOrTypeList) {
  146.   function addType(validator, type) {
  147.     if (!type.id)
  148.       throw new Error("Attempt to addType with missing 'id' property");
  149.     validator.types[type.id] = type;
  150.   }
  151.  
  152.   if (typeOrTypeList instanceof Array) {
  153.     for (var i = 0; i < typeOrTypeList.length; i++) {
  154.       addType(this, typeOrTypeList[i]);
  155.     }
  156.   } else {
  157.     addType(this, typeOrTypeList);
  158.   }
  159. }
  160.  
  161. /**
  162.  * Returns a list of strings of the types that this schema accepts.
  163.  */
  164. chromeHidden.JSONSchemaValidator.prototype.getAllTypesForSchema =
  165.     function(schema) {
  166.   var schemaTypes = [];
  167.   if (schema.type)
  168.     schemaTypes.push(schema.type);
  169.   if (schema.choices) {
  170.     for (var i = 0; i < schema.choices.length; i++) {
  171.       var choiceTypes = this.getAllTypesForSchema(schema.choices[i]);
  172.       schemaTypes = schemaTypes.concat(choiceTypes);
  173.     }
  174.   }
  175.   if (schema['$ref']) {
  176.     var refTypes = this.getAllTypesForSchema(this.types[schema['$ref']]);
  177.     schemaTypes = schemaTypes.concat(refTypes);
  178.   }
  179.   return schemaTypes;
  180. };
  181.  
  182. /**
  183.  * Returns true if |schema| would accept an argument of type |type|.
  184.  */
  185. chromeHidden.JSONSchemaValidator.prototype.isValidSchemaType =
  186.     function(type, schema) {
  187.   if (type == 'any')
  188.     return true;
  189.  
  190.   // TODO(kalman): I don't understand this code. How can type be "null"?
  191.   if (schema.optional && (type == "null" || type == "undefined"))
  192.     return true;
  193.  
  194.   schemaTypes = this.getAllTypesForSchema(schema);
  195.   for (var i = 0; i < schemaTypes.length; i++) {
  196.     if (schemaTypes[i] == "any" || type == schemaTypes[i])
  197.       return true;
  198.   }
  199.  
  200.   return false;
  201. };
  202.  
  203. /**
  204.  * Returns true if there is a non-null argument that both |schema1| and
  205.  * |schema2| would accept.
  206.  */
  207. chromeHidden.JSONSchemaValidator.prototype.checkSchemaOverlap =
  208.     function(schema1, schema2) {
  209.   var schema1Types = this.getAllTypesForSchema(schema1);
  210.   for (var i = 0; i < schema1Types.length; i++) {
  211.     if (this.isValidSchemaType(schema1Types[i], schema2))
  212.       return true;
  213.   }
  214.   return false;
  215. };
  216.  
  217. /**
  218.  * Validates an instance against a schema. The instance can be any JavaScript
  219.  * value and will be validated recursively. When this method returns, the
  220.  * |errors| property will contain a list of errors, if any.
  221.  */
  222. chromeHidden.JSONSchemaValidator.prototype.validate =
  223.     function(instance, schema, opt_path) {
  224.   var path = opt_path || "";
  225.  
  226.   if (!schema) {
  227.     this.addError(path, "schemaRequired");
  228.     return;
  229.   }
  230.  
  231.   // If this schema defines itself as reference type, save it in this.types.
  232.   if (schema.id)
  233.     this.types[schema.id] = schema;
  234.  
  235.   // If the schema has an extends property, the instance must validate against
  236.   // that schema too.
  237.   if (schema.extends)
  238.     this.validate(instance, schema.extends, path);
  239.  
  240.   // If the schema has a $ref property, the instance must validate against
  241.   // that schema too. It must be present in this.types to be referenced.
  242.   if (schema["$ref"]) {
  243.     if (!this.types[schema["$ref"]])
  244.       this.addError(path, "unknownSchemaReference", [ schema["$ref"] ]);
  245.     else
  246.       this.validate(instance, this.types[schema["$ref"]], path)
  247.   }
  248.  
  249.   // If the schema has a choices property, the instance must validate against at
  250.   // least one of the items in that array.
  251.   if (schema.choices) {
  252.     this.validateChoices(instance, schema, path);
  253.     return;
  254.   }
  255.  
  256.   // If the schema has an enum property, the instance must be one of those
  257.   // values.
  258.   if (schema.enum) {
  259.     if (!this.validateEnum(instance, schema, path))
  260.       return;
  261.   }
  262.  
  263.   if (schema.type && schema.type != "any") {
  264.     if (!this.validateType(instance, schema, path))
  265.       return;
  266.  
  267.     // Type-specific validation.
  268.     switch (schema.type) {
  269.       case "object":
  270.         this.validateObject(instance, schema, path);
  271.         break;
  272.       case "array":
  273.         this.validateArray(instance, schema, path);
  274.         break;
  275.       case "string":
  276.         this.validateString(instance, schema, path);
  277.         break;
  278.       case "number":
  279.       case "integer":
  280.         this.validateNumber(instance, schema, path);
  281.         break;
  282.     }
  283.   }
  284. };
  285.  
  286. /**
  287.  * Validates an instance against a choices schema. The instance must match at
  288.  * least one of the provided choices.
  289.  */
  290. chromeHidden.JSONSchemaValidator.prototype.validateChoices =
  291.     function(instance, schema, path) {
  292.   var originalErrors = this.errors;
  293.  
  294.   for (var i = 0; i < schema.choices.length; i++) {
  295.     this.errors = [];
  296.     this.validate(instance, schema.choices[i], path);
  297.     if (this.errors.length == 0) {
  298.       this.errors = originalErrors;
  299.       return;
  300.     }
  301.   }
  302.  
  303.   this.errors = originalErrors;
  304.   this.addError(path, "invalidChoice");
  305. };
  306.  
  307. /**
  308.  * Validates an instance against a schema with an enum type. Populates the
  309.  * |errors| property, and returns a boolean indicating whether the instance
  310.  * validates.
  311.  */
  312. chromeHidden.JSONSchemaValidator.prototype.validateEnum =
  313.     function(instance, schema, path) {
  314.   for (var i = 0; i < schema.enum.length; i++) {
  315.     if (instance === schema.enum[i])
  316.       return true;
  317.   }
  318.  
  319.   this.addError(path, "invalidEnum", [schema.enum.join(", ")]);
  320.   return false;
  321. };
  322.  
  323. /**
  324.  * Validates an instance against an object schema and populates the errors
  325.  * property.
  326.  */
  327. chromeHidden.JSONSchemaValidator.prototype.validateObject =
  328.     function(instance, schema, path) {
  329.   if (schema.properties) {
  330.     for (var prop in schema.properties) {
  331.       // It is common in JavaScript to add properties to Object.prototype. This
  332.       // check prevents such additions from being interpreted as required
  333.       // schema properties.
  334.       // TODO(aa): If it ever turns out that we actually want this to work,
  335.       // there are other checks we could put here, like requiring that schema
  336.       // properties be objects that have a 'type' property.
  337.       if (!schema.properties.hasOwnProperty(prop))
  338.         continue;
  339.  
  340.       var propPath = path ? path + "." + prop : prop;
  341.       if (schema.properties[prop] == undefined) {
  342.         this.addError(propPath, "invalidPropertyType");
  343.       } else if (prop in instance && !isOptionalValue(instance[prop])) {
  344.         this.validate(instance[prop], schema.properties[prop], propPath);
  345.       } else if (!schema.properties[prop].optional) {
  346.         this.addError(propPath, "propertyRequired");
  347.       }
  348.     }
  349.   }
  350.  
  351.   // If "instanceof" property is set, check that this object inherits from
  352.   // the specified constructor (function).
  353.   if (schema.isInstanceOf) {
  354.     if (!isInstanceOfClass(instance, schema.isInstanceOf))
  355.       this.addError(propPath, "notInstance", [schema.isInstanceOf]);
  356.   }
  357.  
  358.   // Exit early from additional property check if "type":"any" is defined.
  359.   if (schema.additionalProperties &&
  360.       schema.additionalProperties.type &&
  361.       schema.additionalProperties.type == "any") {
  362.     return;
  363.   }
  364.  
  365.   // By default, additional properties are not allowed on instance objects. This
  366.   // can be overridden by setting the additionalProperties property to a schema
  367.   // which any additional properties must validate against.
  368.   for (var prop in instance) {
  369.     if (schema.properties && prop in schema.properties)
  370.       continue;
  371.  
  372.     // Any properties inherited through the prototype are ignored.
  373.     if (!instance.hasOwnProperty(prop))
  374.       continue;
  375.  
  376.     var propPath = path ? path + "." + prop : prop;
  377.     if (schema.additionalProperties)
  378.       this.validate(instance[prop], schema.additionalProperties, propPath);
  379.     else
  380.       this.addError(propPath, "unexpectedProperty");
  381.   }
  382. };
  383.  
  384. /**
  385.  * Validates an instance against an array schema and populates the errors
  386.  * property.
  387.  */
  388. chromeHidden.JSONSchemaValidator.prototype.validateArray =
  389.     function(instance, schema, path) {
  390.   var typeOfItems = chromeHidden.JSONSchemaValidator.getType(schema.items);
  391.  
  392.   if (typeOfItems == 'object') {
  393.     if (schema.minItems && instance.length < schema.minItems) {
  394.       this.addError(path, "arrayMinItems", [schema.minItems]);
  395.     }
  396.  
  397.     if (typeof schema.maxItems != "undefined" &&
  398.         instance.length > schema.maxItems) {
  399.       this.addError(path, "arrayMaxItems", [schema.maxItems]);
  400.     }
  401.  
  402.     // If the items property is a single schema, each item in the array must
  403.     // have that schema.
  404.     for (var i = 0; i < instance.length; i++) {
  405.       this.validate(instance[i], schema.items, path + "." + i);
  406.     }
  407.   } else if (typeOfItems == 'array') {
  408.     // If the items property is an array of schemas, each item in the array must
  409.     // validate against the corresponding schema.
  410.     for (var i = 0; i < schema.items.length; i++) {
  411.       var itemPath = path ? path + "." + i : String(i);
  412.       if (i in instance && !isOptionalValue(instance[i])) {
  413.         this.validate(instance[i], schema.items[i], itemPath);
  414.       } else if (!schema.items[i].optional) {
  415.         this.addError(itemPath, "itemRequired");
  416.       }
  417.     }
  418.  
  419.     if (schema.additionalProperties) {
  420.       for (var i = schema.items.length; i < instance.length; i++) {
  421.         var itemPath = path ? path + "." + i : String(i);
  422.         this.validate(instance[i], schema.additionalProperties, itemPath);
  423.       }
  424.     } else {
  425.       if (instance.length > schema.items.length) {
  426.         this.addError(path, "arrayMaxItems", [schema.items.length]);
  427.       }
  428.     }
  429.   }
  430. };
  431.  
  432. /**
  433.  * Validates a string and populates the errors property.
  434.  */
  435. chromeHidden.JSONSchemaValidator.prototype.validateString =
  436.     function(instance, schema, path) {
  437.   if (schema.minLength && instance.length < schema.minLength)
  438.     this.addError(path, "stringMinLength", [schema.minLength]);
  439.  
  440.   if (schema.maxLength && instance.length > schema.maxLength)
  441.     this.addError(path, "stringMaxLength", [schema.maxLength]);
  442.  
  443.   if (schema.pattern && !schema.pattern.test(instance))
  444.     this.addError(path, "stringPattern", [schema.pattern]);
  445. };
  446.  
  447. /**
  448.  * Validates a number and populates the errors property. The instance is
  449.  * assumed to be a number.
  450.  */
  451. chromeHidden.JSONSchemaValidator.prototype.validateNumber =
  452.     function(instance, schema, path) {
  453.  
  454.   // Forbid NaN, +Infinity, and -Infinity.  Our APIs don't use them, and
  455.   // JSON serialization encodes them as 'null'.  Re-evaluate supporting
  456.   // them if we add an API that could reasonably take them as a parameter.
  457.   if (isNaN(instance) ||
  458.       instance == Number.POSITIVE_INFINITY ||
  459.       instance == Number.NEGATIVE_INFINITY )
  460.     this.addError(path, "numberFiniteNotNan", [instance]);
  461.  
  462.   if (schema.minimum !== undefined && instance < schema.minimum)
  463.     this.addError(path, "numberMinValue", [schema.minimum]);
  464.  
  465.   if (schema.maximum !== undefined && instance > schema.maximum)
  466.     this.addError(path, "numberMaxValue", [schema.maximum]);
  467.  
  468.   // Check for integer values outside of -2^31..2^31-1.
  469.   if (schema.type === "integer" && (instance | 0) !== instance)
  470.     this.addError(path, "numberIntValue", []);
  471.  
  472.   if (schema.maxDecimal && instance * Math.pow(10, schema.maxDecimal) % 1)
  473.     this.addError(path, "numberMaxDecimal", [schema.maxDecimal]);
  474. };
  475.  
  476. /**
  477.  * Validates the primitive type of an instance and populates the errors
  478.  * property. Returns true if the instance validates, false otherwise.
  479.  */
  480. chromeHidden.JSONSchemaValidator.prototype.validateType =
  481.     function(instance, schema, path) {
  482.   var actualType = chromeHidden.JSONSchemaValidator.getType(instance);
  483.   if (schema.type != actualType && !(schema.type == "number" &&
  484.       actualType == "integer")) {
  485.     this.addError(path, "invalidType", [schema.type, actualType]);
  486.     return false;
  487.   }
  488.  
  489.   return true;
  490. };
  491.  
  492. /**
  493.  * Adds an error message. |key| is an index into the |messages| object.
  494.  * |replacements| is an array of values to replace '*' characters in the
  495.  * message.
  496.  */
  497. chromeHidden.JSONSchemaValidator.prototype.addError =
  498.     function(path, key, replacements) {
  499.   this.errors.push({
  500.     path: path,
  501.     message: chromeHidden.JSONSchemaValidator.formatError(key, replacements)
  502.   });
  503. };
  504.  
  505. /**
  506.  * Resets errors to an empty list so you can call 'validate' again.
  507.  */
  508. chromeHidden.JSONSchemaValidator.prototype.resetErrors = function() {
  509.   this.errors = [];
  510. };
  511.